import time

from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QDesktopWidget, qApp
from func_timeout import func_set_timeout
from tufup.client import Client

from src.autoupdate.check_update_window import Ui_CheckWindow
from src.myapp import settings


def restart_after_updated():
    qApp.quit()


class UpdateHandler(QObject):
    # 更新完成后重启程序
    update_done_then_restart = pyqtSignal()

    def __init__(self):
        super(UpdateHandler, self).__init__()
        self.ui = Ui_CheckWindow()
        self.window = QMainWindow()
        self.ui.setupUi(self.window)
        self.reset_default()

    def reset_default(self):
        # 绑定按钮事件
        self.ui.pushButton_azgx.clicked.connect(self.exec_update)
        self.ui.pushButton_tgbb.clicked.connect(self.window.close)
        self.update_done_then_restart.connect(restart_after_updated)
        # 隐藏更新进度条和状态编辑框
        self.ui.progressBar.hide()
        self.ui.progressBar.setValue(0)
        self.ui.progressBar.setRange(0, 100)
        self.ui.pushButton_azgx.setEnabled(False)
        self.ui.pushButton_tgbb.setEnabled(False)
        # textEdit 禁止编辑
        self.ui.textEdit.setText("正在检查更新...")
        self.ui.textEdit.setReadOnly(True)
        newest_version = "查询中..."
        self.ui.label_2.setText(newest_version)
        self.ui.label_bbh.setText(f'最新版本:{newest_version} 当前版本: {settings.APP_VERSION}')

    def display_window(self):
        self.window.show()

    def refresh_ui_when_found_new_version(self, newest_version, content_str):
        self.ui.pushButton_azgx.setEnabled(True)
        self.ui.pushButton_tgbb.setEnabled(True)
        self.ui.label_2.setText("")
        self.ui.label_bbh.setText(f'最新版本:{newest_version} 当前版本: {settings.APP_VERSION}')
        self.ui.textEdit.setReadOnly(False)
        self.ui.textEdit.setText(content_str)

    # 定义一个函数使得窗口居中显示
    def center(self, window):
        # 获取屏幕坐标系
        screen = QDesktopWidget().screenGeometry()
        # 获取窗口坐标系
        size = window.geometry()
        new_left = (screen.width() - size.width()) / 2
        new_top = (screen.height() - size.height()) / 2
        window.move(int(new_left), int(new_top))

    def progress_hook(self, bytes_downloaded: int, bytes_expected: int):
        """
        下载进度钩子
        :param bytes_downloaded:
        :param bytes_expected:
        :return:
        """
        progress_percent = bytes_downloaded / bytes_expected * 100
        print(f'\r{progress_percent:.1f}%', end='')
        self.ui.progressBar.setValue(progress_percent.__int__())
        time.sleep(0.2)  # quick and dirty: simulate slow or large download
        if progress_percent >= 100:
            print('Done downloading update package')
            self.update_done_then_restart.emit()

    @func_set_timeout(120)
    def exec_update(self, pre: str, skip_confirmation: bool = False):  # , new_update: TargetMeta = None
        print('安装更新')
        self.ui.progressBar.show()
        # Create update client
        client = Client(
            app_name=settings.APP_NAME,
            app_install_dir=settings.INSTALL_DIR,
            current_version=settings.APP_VERSION,
            metadata_dir=settings.METADATA_DIR,
            metadata_base_url=settings.METADATA_BASE_URL,
            target_dir=settings.TARGET_DIR,
            target_base_url=settings.TARGET_BASE_URL,
            refresh_required=False,
        )

        new_update = client.check_for_updates(pre=pre)
        if new_update:
            # [optional] use custom metadata, if available
            if new_update.custom:
                # for example, show list of changes (see repo_add_bundle.py for definition)
                print('changes in this update:')
                for item in new_update.custom.get('changes', []):
                    print(f'\t- {item}')

            # apply the update
            client.download_and_apply_update(
                skip_confirmation=True,
                progress_hook=self.progress_hook,
                # WARNING: Be very careful with `purge_dst_dir=True`, because
                # this will *irreversibly* delete *EVERYTHING* inside the
                # `app_install_dir`, except any paths specified in
                # `exclude_from_purge`. So, *ONLY* use `purge_dst_dir=True` if
                # you are absolutely certain that your `app_install_dir` does not
                # contain any unrelated content.
                purge_dst_dir=False,
                exclude_from_purge=None,
                log_file_name='install.log',
            )
